/*
    1、注册中心服务端：服务提供者和发现者的管理，针对的是服务发现/注册请求的处理
    2、Rpc服务端：包含一个Rpc服务端，和一个服务注册客户端，需要在启动后先连接注册中心，进行所能提供的服务注册
        Rpc服务端：主要针对Rpc请求进行处理
        服务注册客户端：主要实现向服务注册中心进行服务注册
*/

#pragma once
#include "../common/dispatcher.hpp"
#include "../client/client.hpp"
#include "router.hpp"
#include "registry.hpp"
#include "topic.hpp"

namespace yjz_rpc
{
    namespace server
    {
        class RegistryServer
        {
        public:
            using ptr = std::shared_ptr<RegistryServer>;
            RegistryServer(int port)
                : _dispatcher(std::make_shared<Dispatcher>())
                , _pd_manager(std::make_shared<ProDisManager>())
            {
                auto service_cb = std::bind(&ProDisManager::onServiceRequest, _pd_manager.get(),
                    std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE, service_cb);

                _server = ServerFactory::create(port);
                auto message_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), 
                    std::placeholders::_1, std::placeholders::_2);
                _server->setMessageCallBack(message_cb);

                auto close_cb = std::bind(&RegistryServer::onConnShutdown, this, std::placeholders::_1);
                _server->setCloseCallBack(close_cb);
            }

            void start()
            {
                _server->start();
            }
        private:
            void onConnShutdown(const BaseConnection::ptr& conn)
            {
                _pd_manager->onConnShutDown(conn);
            }
        private:
            BaseServer::ptr _server;
            Dispatcher::ptr _dispatcher;
            ProDisManager::ptr _pd_manager;
        };

        class RpcServer
        {
        public:
            using ptr = std::shared_ptr<RpcServer>;
            RpcServer(const Address& access_addr, const Address& reg_server_addr = Address(), bool enableRegistry = false)  
                : _enableRegistry(enableRegistry)
                , _access_addr(access_addr)
                , _router(std::make_shared<server::RpcRouter>())
                , _dispatcher(std::make_shared<Dispatcher>())
            {
                if (_enableRegistry)
                {
                    _reg_client = std::make_shared<client::RegistryClient>(reg_server_addr.first, reg_server_addr.second);
                }
                auto rpc_cb = std::bind(&RpcRouter::onRpcRequest, _router.get(),
                    std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<RpcRequest>(MType::REQ_RPC, rpc_cb);

                _server = ServerFactory::create(access_addr.second);
                auto message_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), 
                    std::placeholders::_1, std::placeholders::_2);
                _server->setMessageCallBack(message_cb);
            }

            void registryMethod(const ServiceDescribe::ptr& service)
            {
                if (_enableRegistry)
                {
                    _reg_client->serviceRegistry(service->method(), _access_addr);
                }
                _router->registerMethod(service);
            }

            void start()
            {
                _server->start();
            }
        private:
            bool _enableRegistry;
            Address _access_addr;
            RpcRouter::ptr _router;
            BaseServer::ptr _server;
            Dispatcher::ptr _dispatcher;
            client::RegistryClient::ptr _reg_client;
        };

        class TopicServer
        {
        public:
            using ptr = std::shared_ptr<TopicServer>;
            TopicServer(int port)
                : _dispatcher(std::make_shared<Dispatcher>())
                , _topic_manager(std::make_shared<TopicManager>())
            {
                auto topic_cb = std::bind(&TopicManager::onTopicRequest, _topic_manager.get(),
                    std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, topic_cb);

                _server = ServerFactory::create(port);
                auto message_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), 
                    std::placeholders::_1, std::placeholders::_2);
                _server->setMessageCallBack(message_cb);

                auto close_cb = std::bind(&TopicServer::onConnShutdown, this, std::placeholders::_1);
                _server->setCloseCallBack(close_cb);
            }

            void start()
            {
                _server->start();
            }
        private:
            void onConnShutdown(const BaseConnection::ptr& conn)
            {
                _topic_manager->onShutdown(conn);
            }
        private:
            BaseServer::ptr _server;
            Dispatcher::ptr _dispatcher;
            TopicManager::ptr _topic_manager;
        };
    }
}